package com.tjkcht.midware.reader;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.xml.bind.DatatypeConverter;

import com.google.protobuf.InvalidProtocolBufferException;
import com.shhic.itsed.mws.deviceintf.IReaderResultCallback;
import com.shhic.itsed.mws.deviceintf.RawTagField;
import com.shhic.itsed.mws.deviceintf.RawTagReadResult;
import com.shhic.itsed.mws.deviceintf.ReaderCommand;

import io.netty.bootstrap.Bootstrap;
import rdp_msg.Rdp;
import rdp_msg.Rdp.rdp_request;
import rdp_msg.Rdp.rdp_request.Builder;
import rdp_msg.Rdp.rdp_request.HeadType;
import rdp_msg.Rdp.rdp_response;
import rdp_msg.Rdp.rdp_response.ReadResultRara;
import rdp_msg.Rdp.rdp_response.TagReportDataMsg;
import rdp_msg.Rdp.rdp_response.TagReportDataPara;

// TODO: Auto-generated Javadoc
/**
 * The Class Rd30Reader.
 */
public class Rd30Reader extends Reader {

	/** The log. */
	protected Logger log = Logger.getLogger("Rd30Reader");

	/** The response. */
	protected rdp_response response;

	/** The keep alive ack. */
	protected byte[] keepAliveAck;

	/** The deadline. */
	protected long deadline;

	/**
	 * 阅读器结果过滤器
	 * */
	private ReaderResultFilter readerResultFilter;

	/**
	 * Instantiates a new rd 30 reader.
	 *
	 * @param bootstrap
	 *            the bootstrap
	 * @param readerIp
	 *            the reader ip
	 * @param port
	 *            the port
	 */
	public Rd30Reader(Bootstrap bootstrap, String readerIp, int port) {
		super(bootstrap, readerIp, port);
		rdp_request.Builder keepAlive = rdp_request.newBuilder();
		keepAlive.setType(rdp_request.HeadType.keepAliveAck);
		keepAliveAck = keepAlive.build().toByteArray();
		readerResultFilter =new ReaderResultFilter(readerIp);
	}

	/**
	 * Instantiates a new rd 30 reader.
	 *
	 * @param bootstrap the bootstrap
	 * @param readerIp the reader ip
	 * @param port the port
	 * @param initParams the init params
	 */
	public Rd30Reader(Bootstrap bootstrap, String readerIp, int port,Map<String,String> initParams) {
		super(bootstrap, readerIp, port,initParams);
		rdp_request.Builder keepAlive = rdp_request.newBuilder();
		keepAlive.setType(rdp_request.HeadType.keepAliveAck);
		keepAliveAck = keepAlive.build().toByteArray();
		readerResultFilter =new ReaderResultFilter(readerIp);
	}

	/**
	 * Write.
	 *
	 * @param cmd            the cmd
	 * @param timeout the timeout
	 * @param resultCallback            the result callback
	 */
	// 目前默认每个天线的协议和读取的标签区域都是一样的
	public synchronized void write(ReaderCommand cmd, int timeout, IReaderResultCallback resultCallback) {
		this.cmd = cmd;
		this.resultCallback = resultCallback;
		deadline = System.currentTimeMillis() + timeout * 1000;
		sendOut = false;
		if (null == channel) {
			return;
		}
		rdp_request request = Rd30ParaBuilder.getReadRequest(cmd,initParams);
		write(request.toByteArray());
		// 启动下发的指令
		Builder setReq = rdp_request.newBuilder();
		setReq.setType(HeadType.startReaderWork);
		write(setReq.build().toByteArray());
		sendOut = true;
	}

	/**
	 * 补发指令.
	 */
	public synchronized void reWrite() {
		if (null == channel || sendOut || null == cmd) {
			return;
		}
		rdp_request request = Rd30ParaBuilder.getReadRequest(cmd,initParams);
		write(request.toByteArray());
		// 启动下发的指令
		Builder setReq = rdp_request.newBuilder();
		setReq.setType(HeadType.startReaderWork);
		write(setReq.build().toByteArray());
		sendOut = true;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.tjkcht.midware.reader.Reader#read(byte[])
	 */
	public synchronized void read(byte[] msgBytes) {
		log.info(readerIp + " read byte[]=" + DatatypeConverter.printHexBinary(msgBytes));
		try {
			response = Rdp.rdp_response.parseFrom(msgBytes);
			switch (response.getType()) {
				case reportTagData:
//				log.info("report tag data");
					dealReportTagData(response);
					break;
				case startWorkAck:
					log.info("start work");
					break;
				case keepAlive:
					log.info("keepAlive");
					dealKeepAliveAck();
					break;
				case setConfigAck:
					log.info("setConfigAck");
					deadline = -1;
					break;
				case getConfigAck:
					log.info("getConfigAck");
					deadline = -1;
					break;
				case stopWorkAck:
					log.info("stop work");
					break;
				case businessEndEvent:
					log.info("businessEndEvent");
					break;
				case unknownMsg:
					log.warning("unknown meassage!");
					break;
				default:
					log.warning("error type!"+response.getType());
					break;
			}
		} catch (InvalidProtocolBufferException e) {
			log.warning(e.getMessage());
		}
		log.info(readerIp +" handler end");
	}

	/**
	 * Deal keep alive ack.
	 */
	protected void dealKeepAliveAck() {
		write(keepAliveAck);
		if (deadline < 0) {
			return;
		}
		if (sendOut && System.currentTimeMillis() > deadline) {
			warnBack("send meassage time out!");
		}
	}

	/**
	 * Deal report tag data.
	 *
	 * @param response
	 *            the response
	 */
	protected void dealReportTagData(Rdp.rdp_response response) {
		TagReportDataMsg data = response.getTagReportData();
		List<TagReportDataPara> list = data.getTagDataList();
//		log.info("in dealReportTagData:TagReportDataPara length of list is :"+ list.size());
		RawTagReadResult result = null;
		for (int i = 0; i < list.size(); i++) {
			result = buildResult(list.get(i));
			if(!readerResultFilter.isFilter(result.getTagIdentifier())){
				callback(result);
			}
		}
		// 没有清点到标签
		if (null == result) {
			log.info("no tag inventoried!");
			callback(null);
		}
	}

	/**
	 * 构造返回结果.
	 *
	 * @param tagData
	 *            the tag data
	 * @return the raw tag read result
	 */
	private RawTagReadResult buildResult(TagReportDataPara tagData) {
		RawTagReadResult result = new RawTagReadResult();

		String EPC = new String(tagData.getEpc().toByteArray());
		result.setInventoryResult(EPC);
		result.setReaderClass(cmd.getReaderClass());
		result.setReaderId(cmd.getReaderId());
		result.setReaderIp(cmd.getReaderIp());

		tagData.getProtocalType();

		result.setTagProtocol("EPC");// 目前默认为EPC
		result.setAntennaNo(String.valueOf(tagData.getAntId()));

//		log.info("ReadIP:"+cmd.getReaderIp()+"@"+String.valueOf(tagData.getAntId())+", RSSI:"+tagData.getRssi());
		result.setDiscoverCount(1);
		result.setDiscoverTimestamp(tagData.getTime());
		String str = new String(tagData.getEpc().toByteArray());
		result.setInventoryResult(str);
		result.setTagFieldsReadResult(new HashSet<RawTagField>());
		for (ReadResultRara p : tagData.getReadResultList()) {
			RawTagField rtf = cmd.getReadTagFieldList().get(p.getOpid() - 1);
			// rtf.setFieldValue(DatatypeConverter.printHexBinary(p.getReadData().toByteArray()));
			String readData = new String(p.getReadData().toByteArray());
			System.out.println("readData is:"+readData);
			rtf.setFieldValue(readData);
			result.getTagFieldsReadResult().add(rtf);
		}
		return result;
	}

}
